
#include <util/common_macros.h>
#include <util/types.h>
#include <util/mem.h>
#include <util/msg.h>

#include "../../matrix/matrix.h"


static int * __create_int_sequence(int length, int start, int increment) {
	int i, inc;
	int * shift;

	shift = mem_allocn(length, int);
	for (i = 0, inc = start; i < length; i++, inc += increment) shift[i] = inc;

	return shift;
}

int hitmiss(int rows, int columns, real * mat, int sr, int sc, int * se, real * hitmiss) {

	int r, c, _r, i;
	int mr, mc, _mr, mi;
	int d;
	int qtd = 0;

	
	/* Convolve with SE ===================================================== */
	{
		int rf, cf;

		int mrc = (sr - 1) / 2;
		int mcc = (sc - 1) / 2;

		int _2columns_minus_2 = (columns << 1) - 2;
		int _2row_minus_2 = (rows << 1) - 2;

		int * r_shift = __create_int_sequence(rows, 0, columns);
		int hit;

		// <editor-fold defaultstate="collapsed" desc="CONVOLVE">
		for (r = 0, _r = 0; r < rows; r++, _r += columns) {
			for (c = 0; c < columns; c++) {

				i = _r + c;

				hit = 1;

				for (mr = 0, _mr = 0; mr < sr; mr++, _mr += sc) {

					// reflect y boundaries
					rf = r + (mr - mrc);
					if (rf < 0) rf = -rf;
					else if (rf >= rows) rf = _2row_minus_2 - rf;

					for (mc = 0; mc < sc; mc++) {

						mi = _mr + mc;

						if (!se[mi]) continue; // avoid 0 elements

						// reflect x boundaries
						cf = c + (mc - mcc);
						if (cf < 0) cf = -cf;
						else if (cf >= columns) cf = _2columns_minus_2 - cf;

						d = r_shift[rf] + cf;

						if ((mat[d] == 0 && se[mi] != -1) || (mat[d] > 0 && se[mi] != 1)) {
							hit = 0;
							break;
						}

						if (hit == 0) break;
					}
				}
				if (hit == 255) qtd++;
				hitmiss[i] = hit;
			}
		}// </editor-fold>

		free(r_shift);
	}
	return qtd;
}

int imp_image_morph_hitmiss(ImpMatrix * Mat, ImpMatrix * SE, ImpMatrix ** HitMiss) {

	real * mat = NULL;
	real * se = NULL;
	real * hitmiss = NULL;

	int r, c, _r, i;
	int mr, mc, _mr, mi;

	int rows;
	int columns;

	int d;

	long int qtd = 0;

	/* ====================================================================== */
	{
		_verify(Mat);
		_verify(SE);
		_verify(HitMiss);
	}
	/* ====================================================================== */
	{
		mat = Mat->data;
		rows = Mat->rows;
		columns = Mat->columns;
	}
	/* ====================================================================== */
	{
		if (*HitMiss == NULL) (*HitMiss) = imp_matrix_new(rows, columns);
		hitmiss = (*HitMiss)->data;
	}

	/* Convolve with SE ===================================================== */
	{
		int mrows = SE->rows;
		int mcolumns = SE->columns;
		//int msize_minus_1 = SE->size - 1;

		int rf, cf;

		int mrc = (mrows - 1) / 2;
		int mcc = (mcolumns - 1) / 2;

		int _2columns_minus_2 = (columns << 1) - 2;
		int _2row_minus_2 = (rows << 1) - 2;

		se = SE->data;

		int * r_shift = __create_int_sequence(rows, 0, columns);
		int hit;

		// <editor-fold defaultstate="collapsed" desc="CONVOLVE">
		for (r = 0, _r = 0; r < rows; r++, _r += columns) {
			for (c = 0; c < columns; c++) {

				i = _r + c;

				if (r == 10 && c == 10) {
					hit = 2;
				}

				hit = 255;

				for (mr = 0, _mr = 0; mr < mrows; mr++, _mr += mcolumns) {

					// reflect y boundaries
					rf = r + (mr - mrc);
					if (rf < 0) rf = -rf;
					else if (rf >= rows) rf = _2row_minus_2 - rf;

					for (mc = 0; mc < mcolumns; mc++) {

						mi = _mr + mc;
						//mi = msize_minus_1 - mi;

						if (!se[mi]) continue; // avoid 0 elements

						// reflect x boundaries
						cf = c + (mc - mcc);
						if (cf < 0) cf = -cf;
						else if (cf >= columns) cf = _2columns_minus_2 - cf;

						d = r_shift[rf] + cf;

						if ((mat[d] == 0 && se[mi] != -1) || (mat[d] > 0 && se[mi] != 1)) {
							hit = 0;
							break;
						}

						if (hit == 0) break;
					}
				}
				if (hit == 255) qtd++;
				hitmiss[i] = hit;
			}
		}// </editor-fold>

		free(r_shift);
	}
	return qtd;
}
